package com.kinsin.kinsinutil

import android.content.Context
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.junit.After
import org.junit.Assert.*
import org.junit.Test
import org.junit.runner.RunWith
import java.util.concurrent.Executors

@RunWith(AndroidJUnit4::class)
class SharedPreferenceHelperTest {
    private val context = ApplicationProvider.getApplicationContext<Context>()

    @After
    fun tearDown() {
        context.getSharedPreferences("MySharedPreferences", Context.MODE_PRIVATE).edit().clear()
            .commit()
        context.getSharedPreferences("CustomPrefs", Context.MODE_PRIVATE).edit().clear().commit()
        context.getSharedPreferences("AnotherPrefs", Context.MODE_PRIVATE).edit().clear().commit()
    }

    @Test
    fun testSingletonInstance() {
        val instance1 = SharedPreferenceHelper.getInstance(context)
        val instance2 = SharedPreferenceHelper.getInstance(context)
        assertSame("单例实例应该相同", instance1, instance2)
    }

    @Test
    fun testCustomFileNameInstance() {
        val defaultInstance = SharedPreferenceHelper.getInstance(context)
        val customInstance = SharedPreferenceHelper.getInstance(context, "CustomPrefs")
        val anotherCustomInstance = SharedPreferenceHelper.getInstance(context, "AnotherPrefs")

        assertNotSame("不同文件名实例应该不同", defaultInstance, customInstance)
        assertNotSame("不同自定义实例应该不同", customInstance, anotherCustomInstance)
    }

    @Test
    fun testDataIsolationBetweenFiles() {
        val defaultHelper = SharedPreferenceHelper.getInstance(context)
        val customHelper = SharedPreferenceHelper.getInstance(context, "CustomPrefs")

        defaultHelper.put("commonKey", "defaultValue")
        customHelper.put("commonKey", "customValue")

        assertEquals("默认文件应存储正确", "defaultValue", defaultHelper.get("commonKey", ""))
        assertEquals("自定义文件应存储正确", "customValue", customHelper.get("commonKey", ""))
    }

    @Test
    fun testSupportedDataTypes() {
        val helper = SharedPreferenceHelper.getInstance(context)

        // String
        CoroutineScope(Dispatchers.IO).launch {
            helper.put("stringKey", "Hello World")
            delay(500)
            assertEquals("字符串类型验证", "Hello World", helper.get("stringKey", ""))
        }

        // Int
        CoroutineScope(Dispatchers.IO).launch {
            helper.put("intKey", 123)
            delay(500)
            assertEquals("整型验证", 123, helper.get("intKey", 0))
        }

        // Boolean
        CoroutineScope(Dispatchers.IO).launch {
            helper.put("boolKey", true)
            delay(500)
            assertTrue("布尔型验证", helper.get("boolKey", false))
        }

        // Float（使用 delta 参数避免精度问题）
        CoroutineScope(Dispatchers.IO).launch {
            helper.put("floatKey", 3.14f)
            delay(500)
            assertEquals("浮点型验证", 3.14f, helper.get("floatKey", 0f), 0.001f)
        }

        // Long
        CoroutineScope(Dispatchers.IO).launch {
            helper.put("longKey", 123456789L)
            delay(500)
            assertEquals("长整型验证", 123456789L, helper.get("longKey", 0L))
        }
    }


    @Test
    fun testSupportedDataTypesByCommit() {
        val helper = SharedPreferenceHelper.getInstance(context)

        // String
        helper.put("stringKey", "Hello World", true)
        assertEquals("字符串类型验证", "Hello World", helper.get("stringKey", ""))

        // Int
        // Kotlin 泛型与 Java 类型擦除的交互导致类型推断不精确。
        // 所以这里的数字需要指定为 Int 类型
        helper.put("intKeys", 123, true)
        assertEquals("整型验证", 123, helper.get("intKeys", 0.toInt()))

        // Boolean
        helper.put("boolKey", true, true)
        assertTrue("布尔型验证", helper.get("boolKey", false))

        // Float（使用 delta 参数避免精度问题）
        helper.put("floatKey", 3.14f, true)
        assertEquals("浮点型验证", 3.14f, helper.get("floatKey", 0f), 0.001f)

        // Long
        helper.put("longKey", 123456789L, true)
        assertEquals("长整型验证", 123456789L, helper.get("longKey", 0L))
    }

    @Test
    fun testDefaultValueHandling() {
        val helper = SharedPreferenceHelper.getInstance(context)

        assertEquals("字符串默认值", "default", helper.get("nonExistString", "default"))
        assertEquals("整型默认值", 100, helper.get("nonExistInt", 100))
        assertTrue("布尔型默认值", helper.get("nonExistBoolean", true))
    }

    @Test
    fun testRemoveKey() {
        val helper = SharedPreferenceHelper.getInstance(context)
        CoroutineScope(Dispatchers.IO).launch {
            helper.put("tempKey", "toBeRemoved")
            delay(500)
            helper.remove("tempKey")
            delay(500)
            assertEquals("删除后应返回默认值", "notExists", helper.get("tempKey", "notExists"))
        }

    }

    @Test
    fun testClearAllData() {
        val helper = SharedPreferenceHelper.getInstance(context)
        CoroutineScope(Dispatchers.IO).launch {
            helper.put("key1", 1)
            delay(500)
            helper.put("key2", "value")
            delay(500)
            helper.clear()

            assertEquals("清除后key1应默认", 0, helper.get("key1", 0))
            assertTrue("清除后key2应为空", helper.get("key2", "").isEmpty())
        }

    }

    @Test(expected = IllegalArgumentException::class)
    fun testUnsupportedPutType() {
        val helper = SharedPreferenceHelper.getInstance(context)
        helper.put("invalidKey", Any()) // 故意触发异常
    }

    @Test(expected = IllegalArgumentException::class)
    fun testUnsupportedGetType() {
        val helper = SharedPreferenceHelper.getInstance(context)
        helper.get("invalidKey", listOf(1, 2, 3)) // 触发类型检查异常
    }

    @Test
    fun testConcurrentAccess() {
        val helper = SharedPreferenceHelper.getInstance(context)
        val executor = Executors.newFixedThreadPool(5)

        val tasks = List(100) { i ->
            {
                helper.put("concurrentKey", i)
                helper.get("concurrentKey", -1)
            }
        }

        val results = executor.invokeAll(tasks.map { task ->
            java.util.concurrent.Callable { task() }
        })

        results.forEach { future ->
            val result = future.get()
            assertTrue("并发结果应在0-99之间", result in 0..99)
        }
    }
}